package com.xinyue.gateway.service;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.xinyue.gateway.server.message.GateMessagePackage;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.EventExecutor;

/**
 * 此类负责管理角色id和channel的对应关系，并且负责给某个角色id的channel发送消息。
 * 
 * @author 心悦网络科技有限公司 王广帅
 *
 * @Date 2018年6月10日 上午12:03:38
 */
@Service
public class GateChannelGroupService {
	//这里只有获取没有写入，所以是线程安全的
	private Map<Integer, GateChannelGroup> eventLoopMap = new HashMap<>();
	

	/**
	 * 
	 * @Desc 初始化，初始化的时候，会根据线程组的数量对ChannelGroup的管理进行分组。这样可以保证在使用的时候只有读取操作，避免多线程读写eventLoopMap集合。
	 * @param loopGroup
	 * @Author 河南心悦网络科技有限公司 王广帅
	 * @Date 2018年6月3日 下午9:49:30
	 *
	 */
	public void init(EventLoopGroup loopGroup) {
		
		int index = 0;
		//初始化线程组。
		for (Iterator<EventExecutor> ite = loopGroup.iterator(); ite.hasNext();) {
			EventExecutor executor = ite.next();
			GateChannelGroup gameChannelGroup = new GateChannelGroup(executor);
			eventLoopMap.put(index++, gameChannelGroup);
		}
	}

	private int getIndex(Long roleId) {
		int index = roleId.hashCode() % eventLoopMap.size();
		return index;
	}

	private GateChannelGroup getGameChannelGroup(Long userId) {
		int index = this.getIndex(userId);
		//只有这里的读取操作，所以是线程安全的。
		GateChannelGroup gameChannelGroup = eventLoopMap.get(index);
		return gameChannelGroup;
	}

	public void addChannel(Long roleId, Channel channel) {
		GateChannelGroup gameChannelGroup = this.getGameChannelGroup(roleId);
		gameChannelGroup.addChannel(roleId, channel);
	}

	public void removeChannel(Long roleId, ChannelId channelId) {
		GateChannelGroup gameChannelGroup = this.getGameChannelGroup(roleId);
		if (gameChannelGroup != null) {
			gameChannelGroup.removeChannel(roleId, channelId);
		}
	}
	public void closeOldChannelIfExist(ChannelId channelId,long roleId, GateMessagePackage gateMessagePackage) {
        GateChannelGroup gameChannelGroup = this.getGameChannelGroup(roleId);
        gameChannelGroup.closeOldChannelIfExist(channelId, roleId, gateMessagePackage);
    }

	public void writeAndFlush(long roleId,Object message) {
		GateChannelGroup gameChannelGroup = this.getGameChannelGroup(roleId);
		if (gameChannelGroup != null) {
			gameChannelGroup.writeMessage(roleId, message);
		}
	}

}
